package bev.article;

import java.util.Vector;

import java.sql.ResultSet;
import java.sql.SQLException;

import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.JTextField;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JComboBox;

import bev.ConnectionManager;
import bev.HelperUtility;

/**
 * Used to store and work with article data about a person in memory.
 */
public class PersonArticle extends BaseArticle {
    enum Gender {
        MALE, FEMALE
    }

    // Person article data.
    int height, age, weight;
    String hairColor, eyeColor, bio, additionalInfo, physicalDesc;
    Gender gender;

    // Text fields for editing.
    JTextField txtHeight;
    JTextField txtAge;
    JTextField txtWeight;
    JTextField txtHairColor;
    JComboBox<String> cmbGender;
    JTextField txtEyeColor;
    JTextArea txtBio;
    JTextArea txtAdditionalInfo;
    JTextArea txtPhysDesc;

    /**
     * Instantiates a new <i>person</i> article.
     */
    public PersonArticle() {
        super();

        // Default values.
        height = 0;
        age = 0;
        weight = 0;
        gender = Gender.MALE;
        hairColor = "";
        eyeColor = "";
        bio = "";
        additionalInfo = "";
        physicalDesc = "";
    }

    @Override
    public void loadArticle( int id ) {
        id_num = id;

        // Get the results set containing the person.
        try {
            ResultSet rs = ConnectionManager
                    .RunSQLQuery( String
                            .format(
                                    "SELECT id, name, height, age, weight, haircolor, gender, eyecolor, bio, additionalinfo, physicaldescription, created, updated FROM people WHERE id = %d",
                                    id ) );

            if ( rs.next() ) {
                int person_id = rs.getInt( "id" );
                if ( person_id != id ) {
                    System.err.print( "ID from database did not match." );
                    return;
                }

                // Common data.
                name = HelperUtility.stringOrDefault( rs.getString( "name" ) );
                timeCreated = rs.getTimestamp( "created" );
                timeModified = rs.getTimestamp( "updated" );

                // Person data.
                height = rs.getInt( "height" );
                age = rs.getInt( "age" );
                weight = rs.getInt( "weight" );
                hairColor = HelperUtility.stringOrDefault( rs
                        .getString( "haircolor" ) );
                gender = Enum.valueOf( Gender.class, rs.getString( "gender" )
                        .toUpperCase() );
                eyeColor = HelperUtility.stringOrDefault( rs
                        .getString( "eyecolor" ) );
                bio = HelperUtility.stringOrDefault( rs.getString( "bio" ) );
                additionalInfo = HelperUtility.stringOrDefault( rs
                        .getString( "additionalinfo" ) );
                physicalDesc = HelperUtility.stringOrDefault( rs
                        .getString( "physicaldescription" ) );
            }

            ConnectionManager.closeConnection();
        } catch ( SQLException ex ) {
            ex.printStackTrace();
        } catch ( ClassNotFoundException ex ) {
            ex.printStackTrace();
        }
    }

    @Override
    public void storeArticle() {
        try {
            // Get all the person article IDs from the database.
            ResultSet rs = ConnectionManager
                    .RunSQLQuery( "SELECT id FROM people" );

            // Check if this article's ID exists in database.
            boolean exists = false;
            while ( rs.next() ) {
                int person_id = rs.getInt( "id" );
                if ( person_id == id_num ) {
                    exists = true;
                    break;
                }
            }

            // Update article in database if it exists.
            if ( exists ) {
                String query = String
                        .format(
                                // name, height, age, weight, hc, gender, ec,
                                // bio, ai,
                                // pd
                                "UPDATE people SET %s = '%s', %s = %d, %s = %d, %s = %d, %s = '%s', %s = '%s', %s = '%s', %s = '%s', %s = '%s', %s = '%s' WHERE id = %d",
                                "name", ConnectionManager.processEscapeChars( name ),
                                "height", height,
                                "age", age,
                                "weight", weight,
                                "haircolor", ConnectionManager.processEscapeChars( hairColor ),
                                "gender", gender,
                                "eyecolor", ConnectionManager.processEscapeChars( eyeColor ),
                                "bio", ConnectionManager.processEscapeChars( bio ),
                                "additionalInfo", ConnectionManager.processEscapeChars( additionalInfo ),
                                "physicaldescription", ConnectionManager.processEscapeChars( physicalDesc ),
                                id_num );

                System.out.printf( "Update query: '%s'\n", query );
                ConnectionManager.RunSQLUpdateQuery( query );
            }
            // Else insert as a new article.
            else {
                String query = String
                        .format(
                                "INSERT INTO people (name, height, age, weight, haircolor, gender, eyecolor, bio, additionalinfo, physicaldescription, created) VALUES ('%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
                                ConnectionManager.processEscapeChars( name ),
                                height,
                                age,
                                weight,
                                ConnectionManager.processEscapeChars( hairColor ),
                                gender.toString().toLowerCase(),
                                ConnectionManager.processEscapeChars( eyeColor ),
                                ConnectionManager.processEscapeChars( bio ),
                                ConnectionManager.processEscapeChars( additionalInfo ),
                                ConnectionManager.processEscapeChars( physicalDesc ),
                                HelperUtility.formatDatabaseTimeStamp( timeCreated ) );

                System.out.printf( "Insert query: '%s'\n", query );
                ConnectionManager.RunSQLUpdateQuery( query );
            }

            ConnectionManager.closeConnection();
        } catch ( SQLException ex ) {
            ex.printStackTrace();
        } catch ( ClassNotFoundException ex ) {
            ex.printStackTrace();
        }
    }

    @Override
    protected void addBodyText( JTextPane textPane ) {
        // Gender.
        ArticleFormatter.addSmallHeader( textPane, "Gender:\t" );
        ArticleFormatter.addRegular( textPane,
                HelperUtility.capitalizeFirstOnly( gender.toString() ) );
        ArticleFormatter.addNewLine( textPane, 1 );

        // Age.
        ArticleFormatter.addSmallHeader( textPane, "Age:\t\t" );
        ArticleFormatter.addRegular( textPane, String.format( "%d", age ) );
        ArticleFormatter.addNewLine( textPane, 1 );

        // Height.
        ArticleFormatter.addSmallHeader( textPane, "Height:\t" );
        ArticleFormatter.addRegular( textPane, String.format( "%d", height ) );
        ArticleFormatter.addNewLine( textPane, 1 );

        // Weight.
        ArticleFormatter.addSmallHeader( textPane, "Weight:\t" );
        ArticleFormatter.addRegular( textPane, String.format( "%d", weight ) );
        ArticleFormatter.addNewLine( textPane, 1 );

        // Hair Color.
        if ( hairColor.length() > 0 ) {
            ArticleFormatter.addSmallHeader( textPane, "Hair Color:\t" );
            ArticleFormatter.addRegular( textPane, hairColor );
            ArticleFormatter.addNewLine( textPane, 1 );
        }

        // Eye Color.
        if ( eyeColor.length() > 0 ) {
            ArticleFormatter.addSmallHeader( textPane, "Eye Color:\t" );
            ArticleFormatter.addRegular( textPane, eyeColor );
            ArticleFormatter.addNewLine( textPane, 1 );
        }

        ArticleFormatter.addNewLine( textPane, 1 );

        // Bio.
        if ( bio.length() > 0 ) {
            ArticleFormatter.addSmallHeader( textPane, "Bio" );
            ArticleFormatter.addNewLine( textPane, 1 );
            ArticleFormatter.addRegular( textPane, bio );
            ArticleFormatter.addNewLine( textPane, 2 );
        }

        // Additional Info.
        if ( additionalInfo.length() > 0 ) {
            ArticleFormatter.addSmallHeader( textPane, "Additional Info" );
            ArticleFormatter.addNewLine( textPane, 1 );
            ArticleFormatter.addRegular( textPane, additionalInfo );
            ArticleFormatter.addNewLine( textPane, 2 );
        }

        // Physical Description
        if ( physicalDesc.length() > 0 ) {
            ArticleFormatter.addSmallHeader( textPane, "Physical Description" );
            ArticleFormatter.addNewLine( textPane, 1 );
            ArticleFormatter.addRegular( textPane, physicalDesc );
            ArticleFormatter.addNewLine( textPane, 1 );
        }
    }

    @Override
    protected JPanel getBodyEditControls() {
        ArticleEditPanel panel = new ArticleEditPanel();

        // Instantiate/set up the fields.

        txtAge = new JTextField( String.format( "%d", age ) );
        txtHeight = new JTextField( String.format( "%d", height ) );
        txtWeight = new JTextField( String.format( "%d", weight ) );
        txtHairColor = new JTextField( hairColor );
        txtEyeColor = new JTextField( eyeColor );

        // Gender combo box.
        Vector<String> genders = new Vector<String>();
        for ( Gender g : Gender.values() )
            genders.add( g.toString().toLowerCase() );
        cmbGender = new JComboBox<String>( genders );
        cmbGender.setSelectedItem( gender.toString().toLowerCase() );

        // Bio.
        txtBio = new JTextArea( bio );
        txtBio.setLineWrap( true );
        JScrollPane spBio = new JScrollPane( txtBio );
        spBio.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );

        // Additional Info.
        txtAdditionalInfo = new JTextArea( additionalInfo );
        txtAdditionalInfo.setLineWrap( true );
        JScrollPane spAddInfo = new JScrollPane( txtAdditionalInfo );
        spAddInfo
                .setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );

        // Physical Description.
        txtPhysDesc = new JTextArea( physicalDesc );
        txtPhysDesc.setLineWrap( true );
        JScrollPane spPhysDesc = new JScrollPane( txtPhysDesc );
        spPhysDesc
                .setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED );

        // Add the fields to the article edit view.

        panel.addComponent( "Age", txtAge, ArticleEditPanel.getSmallFieldSize() );
        panel.addComponent( "Height", txtHeight,
                ArticleEditPanel.getSmallFieldSize() );
        panel.addComponent( "Weight", txtWeight,
                ArticleEditPanel.getSmallFieldSize() );
        panel.addComponent( "Gender", cmbGender,
                ArticleEditPanel.getSmallFieldSize() );
        panel.addComponent( "Hair Color", txtHairColor,
                ArticleEditPanel.getMediumFieldSize() );
        panel.addComponent( "Eye Color", txtEyeColor,
                ArticleEditPanel.getMediumFieldSize() );
        panel.commitComponents();

        panel.addComponent( "Bio", spBio );
        panel.addComponent( "Additional Info", spAddInfo );
        panel.addComponent( "Physical Description", spPhysDesc );
        panel.commitComponents();

        return panel;
    }

    @Override
    protected void saveCustomEditData() {
        height = HelperUtility.getTextAsIntNullCheck( txtHeight );
        age = HelperUtility.getTextAsIntNullCheck( txtAge );
        weight = HelperUtility.getTextAsIntNullCheck( txtWeight );
        hairColor = HelperUtility.getTextNullCheck( txtHairColor );
        gender = Enum.valueOf( Gender.class,
                ( (String) cmbGender.getSelectedItem() ).toUpperCase() );
        eyeColor = HelperUtility.getTextNullCheck( txtEyeColor );
        bio = HelperUtility.getTextNullCheck( txtBio );
        additionalInfo = HelperUtility.getTextNullCheck( txtAdditionalInfo );
        physicalDesc = HelperUtility.getTextNullCheck( txtPhysDesc );
    }

    @Override
    protected boolean validateBodyEditFields() {
        // Height.
        if ( !validateInt( txtHeight.getText(), "Height" ) )
            return false;

        // Age.
        if ( !validateInt( txtAge.getText(), "Age" ) )
            return false;

        // Weight.
        if ( !validateInt( txtWeight.getText(), "Weight" ) )
            return false;

        return true;
    }
}
